import 'package:simulator/arch/mcs51/mcs51.dart';
import 'package:simulator/core/interrupt.dart';
import 'package:simulator/core/module.dart';
import 'package:simulator/core/op_code.dart';
import 'package:simulator/core/ram_rom.dart';
import 'package:simulator/hardware/mcs51/interrupt.dart';
import 'package:simulator/utils/options.dart';
import 'package:simulator/utils/utils.dart';
import 'package:win32/win32.dart';

enum MCUType { unkown, mcs51, arm, riscv, x86 }

enum MCUState { unkown, init, running, debug, next, exit }

extension MCUTypeOp on MCUType {
  static MCUType getType(String name) {
    if (MCUType.mcs51.name == name) {
      return MCUType.mcs51;
    } else if (MCUType.arm.name == name) {
      return MCUType.arm;
    } else if (MCUType.riscv.name == name) {
      return MCUType.riscv;
    } else if (MCUType.x86.name == name) {
      return MCUType.x86;
    }
    return MCUType.unkown;
  }
}

class MCU {
  final String name;
  final MCUType type;
  MCU({this.name = '', this.type = MCUType.unkown});
  late final List<OpCode> opCode;
  late final OpCode? Function(int opcode) restOpCode;
  late final List<Module> module;
  late final List<Interrupt> interrupt;
  int _pc = 0;

  ///获取芯片配置表
  ///
  ///如果module不为空则加载配置文件中的属性
  ///
  ///命令行大于配置文件
  factory MCU.getConfig(CMD cmd) {
    late List<OpCode> opCode;
    late final OpCode? Function(int opcode) restOpCode;
    late List<Interrupt> interrupt;
    late final Function interruptHandle;

    ///默认导出的模块
    late final List<Module> module;
    switch (cmd.arch) {
      case MCUType.mcs51:
        opCode = opMCS51Code;
        restOpCode = mcs51RestOpCode;
        module = mcs51Module;
        interrupt = mcs51Interrupt;
        interruptHandle = mcs51InterruptHandle;
        break;
      case MCUType.arm:
      case MCUType.riscv:
      case MCUType.x86:
      case MCUType.unkown:
        Utils.getInstance().abort('can\'t get op for ${cmd.arch.name}');
    }

    ///外部配置文件的module,添加动态module
    if (cmd.module != null) {
      module.addAll({});
    }

    return MCU(type: cmd.arch)
      ..opCode = opCode
      ..restOpCode = restOpCode
      ..interrupt = interrupt
      ..interruptHandle = interruptHandle
      ..module = module;
  }

  ///程序复位
  void reset() {
    _pc = 0;
    for (var r in module) {
      for (var element in r.registers) {
        element.reset();
      }
    }
  }

  int exec() {
    try {
      int code = RomAndRam.getInstance().getCode(_pc++);
      OpCode op = opCode.firstWhere((e) => e.code == code, orElse: () {
        OpCode? op = restOpCode(code);
        if (op == null) {
          throw code.toHexString(8);
        }
        return op;
      });
      var data = RomAndRam.getInstance().getData(_pc, op.data);
      _pc += op.data;

      ///List<int> args, int code, int pc
      op.callback.call(data, code, _pc);

      return op.time;
    } catch (e) {
      Utils.getInstance().abort('op $e not exist');
    }
    return 0;
  }

  ///每条指令周期都需要判断是否有中断
  late final Function interruptHandle;

  set pc(int value) => _pc = value;
}
